package com.yanqu.road.server.gameplayer.module.activity.bulletscreen;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.bulletscreen.BulletScreenUserData;
import com.yanqu.road.entity.activity.bulletscreen.ActivityBarrageMessage;
import com.yanqu.road.entity.enums.eChannelType;
import com.yanqu.road.entity.enums.eMessageType;
import com.yanqu.road.logic.bussiness.activity.BulletScreenBusiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.pb.activity.BulletScreenProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.manger.ForbiddenWordMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.activity.bulletscreen.ActivityBulletScreenMgr;
import com.yanqu.road.server.manger.activity.newyear2023.FireWorkMgr;
import com.yanqu.road.server.manger.activity.springdinner.SpringDinnerMgr;
import com.yanqu.road.server.manger.activity.wishpool.WishPoolMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.manger.thirdparty.ThirdPartyMgr;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.LocalDateTimeHelper;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class BulletScreenModule extends GeneralModule {

    Map<Integer, BulletScreenUserData> userDataMap = new ConcurrentHashMap<>();

    public BulletScreenModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        List<Integer> activityIdList = getAllActivityIdList();
        userDataMap = BulletScreenBusiness.getBulletScreenUserData(player.getUserId(), activityIdList);
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return false;
    }

    @Override
    public boolean saveData() {
        for(Map.Entry<Integer, BulletScreenUserData> userDataEntry : userDataMap.entrySet()) {
            BulletScreenUserData userData = userDataEntry.getValue();
            if(userData.isInsertOption()){
                BulletScreenBusiness.addBulletScreenUserData(userData);
            }else if(userData.isUpdateOption()){
                BulletScreenBusiness.updateBulletScreenBusiness(userData);
            }
        }
        return true;
    }

    private List<Integer> getAllActivityIdList(){
        List<Integer> activityIdList = new ArrayList<>();
        int activityId = WishPoolMgr.getInShowTimeActivityId();
        if(activityId > 0){
            activityIdList.add(activityId);
        }
        //粘液饭也要
        activityId = SpringDinnerMgr.getShowTimeActivityId();
        if(activityId > 0){
            activityIdList.add(activityId);
        }

        //烟花祈愿年夜饭2023
        activityId = FireWorkMgr.getRedPacketActivityId();
        if(activityId > 0){
            activityIdList.add(activityId);
        }

        return activityIdList;
    }

    @Override
    public void afterLogin() {
        resetOneDay();
        checkUserData();
        syncUserData();
    }

    private void checkUserData() {
        List<Integer> activityIdList = getAllActivityIdList();
        for(int activityId : activityIdList){
            if(!userDataMap.containsKey(activityId)){
                if(SpringDinnerMgr.getShowTimeActivityId() == activityId){
                    //新加的年夜饭弹幕
                    initSpringUserData(activityId);
                }else if(FireWorkMgr.getRedPacketActivityId() == activityId){
                    //新年祈愿弹幕
                    initFireWorkUserData(activityId);
                }else{
                    initUserData(activityId);
                }
            }
        }
    }

    public void syncUserData() {
        BulletScreenProto.BulletScreenUserDataSyncMsg.Builder syncMsg = BulletScreenProto.BulletScreenUserDataSyncMsg.newBuilder();
        syncMsg.addAllUserData(getUserDataMsg());
        player.sendPacket(Protocol.U_ACTIVITY_SYNC_BULLET_SCREEN_USER_DATA, syncMsg);
    }

    /**
     * 初始化用户数据
     */
    public void initUserData(int activityId) {
        if(!userDataMap.containsKey(activityId)) {
            BulletScreenUserData userData = new BulletScreenUserData();
            userData.setUserId(player.getUserId());
            userData.setActivityId(activityId);
            userData.setResetTime(System.currentTimeMillis());
            userData.setCanBarrageTimes(GameConfig.ACTIVITY_ONE_DAY_BULLET_SCREEN_TIMES);
            userData.setInsertOption();
            userDataMap.put(activityId, userData);
        }
    }

    public void initSpringUserData(int activityId) {
        if(!userDataMap.containsKey(activityId)) {
            BulletScreenUserData userData = new BulletScreenUserData();
            userData.setUserId(player.getUserId());
            userData.setActivityId(activityId);
            userData.setResetTime(System.currentTimeMillis());
            userData.setCanBarrageTimes(1);//默认给一次机会让他发,不然手速太快
            userData.setInsertOption();
            userDataMap.put(activityId, userData);
        }
    }

    public void initFireWorkUserData(int activityId) {
        if(!userDataMap.containsKey(activityId)) {
            BulletScreenUserData userData = new BulletScreenUserData();
            userData.setUserId(player.getUserId());
            userData.setActivityId(activityId);
            userData.setResetTime(System.currentTimeMillis());
            userData.setCanBarrageTimes(1);
            userData.setInsertOption();
            userDataMap.put(activityId, userData);
        }
    }

    //抢一次红包多一次能发的机会
    public void robAddCanBarrageTimes(int activityId){
        BulletScreenUserData userData = userDataMap.get(activityId);
        if(userData != null){
            synchronized (userData){
                userData.setCanBarrageTimes(userData.getCanBarrageTimes() + 1);
            }
        }
    }

    /**
     * 每日重置
     */
    public void resetOneDay() {
        long today = LocalDateTimeHelper.getZeroTimeTimeStamp();
        boolean needSync = false;
        for(Map.Entry<Integer, BulletScreenUserData> userDataEntry : userDataMap.entrySet()) {
            //年夜饭不用重置了，可以一直发
            if(userDataEntry.getKey() == SpringDinnerMgr.getShowTimeActivityId())continue;
            if(userDataEntry.getKey() == FireWorkMgr.getRedPacketActivityId())continue;
            BulletScreenUserData userData = userDataEntry.getValue();
            long lastResetDay = LocalDateTimeHelper.getZeroTimeTimeStamp(userData.getResetTime());
            if (today > lastResetDay) {
                userData.setCanBarrageTimes(GameConfig.ACTIVITY_ONE_DAY_BULLET_SCREEN_TIMES);
                userData.setResetTime(System.currentTimeMillis());
                needSync = true;
            }
        }
        if(needSync){
            syncUserData();
        }
    }

    /**
     * 获取弹幕次数
     */
    public List<BulletScreenProto.BulletScreenUserDataTemp> getUserDataMsg() {
        List<BulletScreenProto.BulletScreenUserDataTemp> builderList = new ArrayList<>();
        for(Map.Entry<Integer, BulletScreenUserData> userDataEntry : userDataMap.entrySet()) {
            BulletScreenUserData userData = userDataEntry.getValue();
            builderList.add(parseUserDataBuilder(userData).build());
        }
        return builderList;
    }

    private BulletScreenProto.BulletScreenUserDataTemp.Builder parseUserDataBuilder(BulletScreenUserData userData) {
        BulletScreenProto.BulletScreenUserDataTemp.Builder builder = BulletScreenProto.BulletScreenUserDataTemp.newBuilder();
        builder.setActivityId(userData.getActivityId());
        builder.setBulletTime(userData.getCanBarrageTimes() + userData.getBuyBarrageTimes());
        return builder;
    }

    /**
     * 获取弹幕次数
     */
    public BulletScreenProto.BulletScreenUserDataTemp.Builder getUserDataMsg(int activityId) {
        BulletScreenUserData userData = userDataMap.get(activityId);
        if(userData != null){
            return parseUserDataBuilder(userData);
        }
        return null;
    }

    /**
     * 弹幕（独立线程执行）
     * @param content 内容
     * @return
     */
    public void bulletScreen(int activityId, String content) {
        BulletScreenUserData userData = userDataMap.get(activityId);
        if(userData != null){
            //预先判断次数
            synchronized (userData) {
                if (userData.getCanBarrageTimes() == 0 && userData.getBuyBarrageTimes() == 0) {
                    sendErrorCodeResp(activityId, GameErrorCode.E_ACTIVITY_BARRAGE_TIMES_NOT_ENOUGH);
                    return;
                }
            }

            String checkContent = content;
            String[] split = content.split("的红包！",2);
            if (split.length > 1) {
                checkContent = split[1];
            }

            // 渠道规则判定
            int channelId = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId()).getChannelId();
            if (channelId == eChannelType.InnerChannel.getValue() || channelId == eChannelType.MainLandInnerTest.getValue()) {
                if(ForbiddenWordMgr.isForbidden(checkContent)){
                    sendErrorCodeResp(activityId, GameErrorCode.E_ACTIVITY_BARRAGE_FORBIDDEN);
                    return;
                }
            }else if(eChannelType.needLocalForbidden(channelId)){
                if(ForbiddenWordMgr.isForbidden(checkContent)){
                    sendErrorCodeResp(activityId, GameErrorCode.E_ACTIVITY_BARRAGE_FORBIDDEN);
                    return;
                }
            }else {
                try {
                    int state = ThirdPartyMgr.uploadChatDataGetState(player, checkContent, (int) (System.currentTimeMillis() / 1000), eMessageType.ActivityBulletScreen.getValue(), activityId, null);
                    if (state != 1) {
                        sendErrorCodeResp(activityId, GameErrorCode.E_ACTIVITY_BARRAGE_FORBIDDEN);
                        return;
                    }
                }catch (Exception e){
                    log.error(e.getMessage(), e);
                    if(ForbiddenWordMgr.isForbidden(checkContent)){
                        sendErrorCodeResp(activityId, GameErrorCode.E_ACTIVITY_BARRAGE_FORBIDDEN);
                        return;
                    }
                }
            }

            synchronized (userData) {
                //重复判断次数
                if (userData.getCanBarrageTimes() == 0 && userData.getBuyBarrageTimes() == 0) {
                    sendErrorCodeResp(activityId, GameErrorCode.E_ACTIVITY_BARRAGE_TIMES_NOT_ENOUGH);
                    return;
                }
                if (ActivityBulletScreenMgr.isCrossActivity(activityId)){
                    //跨服弹幕
                    if(userData.getCanBarrageTimes() > 0){
                        userData.setCanBarrageTimes(userData.getCanBarrageTimes() - 1);
                    }else if(userData.getBuyBarrageTimes() > 0){
                        userData.setBuyBarrageTimes(userData.getBuyBarrageTimes() - 1);
                    }
                    syncUserData();
                    BulletScreenProto.CrossBulletScreenContentReqMsg.Builder launchMsg = BulletScreenProto.CrossBulletScreenContentReqMsg.newBuilder();
                    launchMsg.setActivityId(activityId);
                    launchMsg.setContent(content);
                    launchMsg.setNickName(player.getUserInfo().getNickName());
                    GamePlayerMgr.sendPacket(player.getUserId(), YanQuMessageUtils.buildMessage(Protocol.C_CROSS_ACTIVITY_BULLET_SCREEN_COMMENTS, launchMsg));
                    return;
                }
                ActivityBarrageMessage msg = ActivityBulletScreenMgr.addBarrageMessage(activityId, content, player.getUserId());
                if(msg == null){
                    sendErrorCodeResp(activityId, GameErrorCode.E_ACTIVITY_BARRAGE_CONTENT_NO_SUPPORT);
                    return;
                }
                if(userData.getCanBarrageTimes() > 0){
                    userData.setCanBarrageTimes(userData.getCanBarrageTimes() - 1);
                }else if(userData.getBuyBarrageTimes() > 0){
                    userData.setBuyBarrageTimes(userData.getBuyBarrageTimes() - 1);
                }
                bulletResponse(activityId, content, userData, msg);
            }
        }
    }

    public int bulletScreenFromCross(int activityId, int crossRet, BulletScreenProto.ActivityBarrageMessageTemp messageTemp){
        BulletScreenUserData userData = userDataMap.get(activityId);
        if(userData != null) {
            BulletScreenProto.BulletScreenContentRespMsg.Builder respMsg = BulletScreenProto.BulletScreenContentRespMsg.newBuilder();
            respMsg.setRet(0);
            respMsg.setActivityId(activityId);
            BulletScreenProto.ActivityBarrageMessageTemp.Builder tempBuilder = messageTemp.toBuilder();
            tempBuilder.setNickName(player.getUserInfo().getNickName());
            respMsg.setMsg(tempBuilder.build());
            respMsg.setBulletTime(userData.getCanBarrageTimes() + userData.getBuyBarrageTimes());
            player.sendPacket(ClientProtocol.U_ACTIVITY_BULLET_SCREEN_COMMENTS, respMsg);
        }
        return 0;
    }


    /**
     * 弹幕返回
     */
    private void bulletResponse(int activityId, String content, BulletScreenUserData userData, ActivityBarrageMessage msg) {
        BulletScreenProto.BulletScreenContentRespMsg.Builder respMsg = BulletScreenProto.BulletScreenContentRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setActivityId(activityId);
        BulletScreenProto.ActivityBarrageMessageTemp.Builder temp = ActivityBulletScreenMgr.parseBarrageMessageBuilder(msg, content, msg.getActivityId());
        temp.setNickName(player.getUserInfo().getNickName());
        respMsg.setMsg(temp);
        respMsg.setBulletTime(userData.getCanBarrageTimes() + userData.getBuyBarrageTimes());
        player.sendPacket(ClientProtocol.U_ACTIVITY_BULLET_SCREEN_COMMENTS, respMsg);
    }

    private void sendErrorCodeResp(int activityId, int errorCode){
        BulletScreenProto.BulletScreenContentRespMsg.Builder respMsg = BulletScreenProto.BulletScreenContentRespMsg.newBuilder();
        respMsg.setRet(errorCode);
        respMsg.setActivityId(activityId);
        player.sendPacket(ClientProtocol.U_ACTIVITY_BULLET_SCREEN_COMMENTS, respMsg);
    }

    /**
     * 弹幕列表（未读)
     * @return
     */
    public int getBulletScreenMsgList(int activityId) {
        BulletScreenUserData userData = userDataMap.get(activityId);
        if(userData != null){
            // 跨服弹幕
            if(ActivityBulletScreenMgr.isCrossActivity(activityId)){
                getCrossBulletScreenMsgList(activityId, userData);
                return 0;
            }

            ActivityBulletScreenMgr.addMsgListener(activityId, player.getUserId());
            List<ActivityBarrageMessage> list = ActivityBulletScreenMgr.getMessageList(activityId);
            List<ActivityBarrageMessage> syncList = new ArrayList<>();
            long zeroTime = LocalDateTimeHelper.getZeroTimeTimeStamp();

            checkReadDataValid(userData, list.size(), list.size() > 0 ? list.get(0).getPostTime(): 0);

            for(ActivityBarrageMessage msg : list){
                //消息id大于历史已读且是当天，且不在实时推送中（已读）
                if(msg.getContentId() > userData.getReadContentId() && msg.getPostTime() >=zeroTime && !userData.getReadContentIdList().contains(msg.getContentId())){
                    syncList.add(msg);
                }
            }
            BulletScreenProto.BulletScreenContentListRespMsg.Builder respMsg = ActivityBulletScreenMgr.getMsgListBuilder(syncList);
            respMsg.setActivityId(activityId);
            player.sendPacket(ClientProtocol.U_ACTIVITY_LIST_BULLET_SCREEN_COMMENTS, respMsg);

            removeRealTimeReadContentId(userData);
        }
        return 0;
    }

    /**
     * 清理推送已读LIST
     */
    private void removeRealTimeReadContentId(BulletScreenUserData userData) {
        synchronized (userData){
            List<Long> idList = new ArrayList<>(userData.getReadContentIdList());
            Iterator<Long> iterator = idList.iterator();
            while (iterator.hasNext()){
                long id = iterator.next();
                if(id < userData.getReadContentId()){
                    userData.removeRealTimeReadContentId(id);
                }else {
                    break;
                }
            }
        }
    }

    /**
     * 跨服返回的跨服弹幕
     */
    public int bulletScreenMsgListFromCross(int activityId, long totalMsgSize, long firstMsgTime, List<BulletScreenProto.ActivityBarrageMessageTemp> list) {
        BulletScreenUserData userData = userDataMap.get(activityId);
        if(userData != null){

            checkReadDataValid(userData, totalMsgSize, firstMsgTime);

            List<BulletScreenProto.ActivityBarrageMessageTemp> syncList = new ArrayList<>();
            for(BulletScreenProto.ActivityBarrageMessageTemp msg : list){
                //消息不在实时推送中（已读）
                if(!userData.getReadContentIdList().contains(msg.getContentId())){
                    syncList.add(msg);
                }
            }
            log.info("user {} get Barrage message {}:{}", player.getUserId(), activityId, syncList.size());
            BulletScreenProto.BulletScreenContentListRespMsg.Builder respMsg = BulletScreenProto.BulletScreenContentListRespMsg.newBuilder();
            respMsg.setRet(0);
            respMsg.addAllMsg(syncList);
            player.sendPacket(ClientProtocol.U_ACTIVITY_LIST_BULLET_SCREEN_COMMENTS, respMsg);

            removeRealTimeReadContentId(userData);
        }
        return 0;
    }

    /**
     * 获取跨服弹幕列表（未读）
     */
    private void getCrossBulletScreenMsgList(int activityId, BulletScreenUserData userData) {
        BulletScreenProto.CrossBulletScreenContentListReqMsg.Builder crossReqMsg = BulletScreenProto.CrossBulletScreenContentListReqMsg.newBuilder();
        crossReqMsg.setActivityId(activityId);
        crossReqMsg.setLastReadTime(userData.getLastReadTime());
        crossReqMsg.setReadContentId(userData.getReadContentId());
        player.sendPacket(Protocol.C_CROSS_ACTIVITY_LIST_BULLET_SCREEN_COMMENTS, crossReqMsg);
    }


    /**
     * 检查玩家已读是否合理(针对弹幕不入库的处理)
     */
    private void checkReadDataValid(BulletScreenUserData userData, long size, long firstMsgTime) {
        //已读大于消息总个数，数据已脏，重置
        if(userData.getReadContentId() > size){
            synchronized (userData) {
                userData.setReadContentId(0);
                userData.setReadContentIdList(new ArrayList<>());
            }
        }else if(size > 0){
            //最后读取时间小于第一条消息,重置
            if(userData.getLastReadTime() < firstMsgTime){
                synchronized (userData) {
                    userData.setReadContentId(0);
                    userData.setReadContentIdList(new ArrayList<>());
                }
            }else {
                // 实时已读最大消息id大于现有消息总数
                int length = userData.getReadContentIdList().size();
                if(length > 0){
                    long max = userData.getReadContentIdList().get(length - 1);
                    if(size < max) {
                        synchronized (userData) {
                            List<Long> idList = new ArrayList<>(userData.getReadContentIdList());
                            Iterator<Long> iterator = idList.iterator();
                            while (iterator.hasNext()) {
                                long id = iterator.next();
                                if (id > size) {
                                    userData.removeRealTimeReadContentId(id);
                                } else {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 标识已读
     * @param contentId
     * @param type  0：主动请求的历史列表被读；1:定时推送的列表被读
     * @return
     */
    public int setBulletScreenReadId(int activityId, long contentId, int type) {
        BulletScreenUserData userData = userDataMap.get(activityId);
        if(userData != null && contentId > 0){
            synchronized (userData) {
                if (type == 0) {
                    userData.setReadContentId(contentId);
                } else if (type == 1) {
                    userData.addRealTimeReadContentId(contentId);
                }
                userData.setLastReadTime(System.currentTimeMillis());
            }
        }
        return 0;
    }
}
